import {
  FormInstance,
  PaginationProps,
  Table,
  TableProps,
  TabsProps,
} from 'antd';
import { ConfigContext } from 'antd/es/config-provider/context';
import { ColumnType } from 'antd/es/table';
import React, {
  ReactElement,
  ReactNode,
  Ref,
  forwardRef,
  useContext,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import type { SizeInfo } from 'ym-design';
import { YmResizeObserver, useAntdTableScrollY } from 'ym-design';
import { isObjectValueEqual } from '../utils/obj/equal';
import { OpearteButtonGroup } from './OpearteButtonGroup';
import { TableSearchForm, TableSearchFormProps } from './SearchForm';
import { TableTabs, TableTabsProps } from './TabsBar';
import { TableToolBar, TableToolBarProps, ToolBarProps } from './ToolBar';
import { useStyles } from './style';
import './style/index.less';
export interface YmColumnType<RecordType>
  extends Omit<ColumnType<RecordType>, 'key'> {
  hidden?: boolean;
  ableHidden?: boolean;
  /**
   * @description 设置列顺序组件必须有key
   */
  key: React.Key;
  fixed?: any;
}

export interface YmColumnGroupType<RecordType>
  extends Omit<YmColumnType<RecordType>, 'dataIndex'> {
  children: YmColumnsType<RecordType>;
}

export type YmColumnsType<RecordType> = (
  | YmColumnType<RecordType>
  | YmColumnGroupType<RecordType>
)[];

export type YmToolBarProps = Pick<
  ToolBarProps,
  'items' | 'onColumnsChange' | 'prefixNode' | 'onBtnClick'
>;

type TempVar<RecordType> = Parameters<
  NonNullable<TableProps<RecordType>['onChange']>
>;

type TableParams<RecordType> = {
  page?: TempVar<RecordType>[0] & {
    pageIndex?: number;
  };
  filters?: TempVar<RecordType>[1];
  sorter?: TempVar<RecordType>[2];
  extra?: TempVar<RecordType>[3];
};

type RequiredKey =
  | 'defaultCurrent'
  | 'defaultPageSize'
  | 'current'
  | 'pageSize';
type MyPagination = Omit<PaginationProps, RequiredKey> &
  Required<Pick<PaginationProps, RequiredKey>>;

type TabsParams = NonNullable<TabsProps['items']>[number];

type RenderNode = {
  formNode: ReactNode;
  tabsNode: ReactNode;
  toolBarNode: ReactNode;
  tableNode: ReactNode;
};

type onChangeParams<RecordType, FormValue> = [
  TableParams<RecordType>,
  FormValue | undefined,
  TabsParams | undefined,
];
export interface YmTablePorps<RecordType = any, FormValue = any>
  extends Omit<
    TableProps<RecordType>,
    'columns' | 'onChange' | 'scroll' | 'children' | 'pagination'
  > {
  /**
   * @desc 内置Tabs的配置
   */
  tabs?: TableTabsProps['tabs'];
  /**
   * @desc 内置查询Form的配置
   */
  searchForm?: TableSearchFormProps<FormValue>['searchFrom'];
  /**
   * @desc 外层元素的style配置
   */
  wrapperStyle?: React.CSSProperties;
  /**
   * @desc 内置工具栏的配置
   */
  toolBar?: TableToolBarProps['toolbar'];
  /**
   * @desc 扩展的tableColumns配置
   */
  columns?: YmColumnsType<RecordType>;
  /**
   * @desc 自动控制的时候调用onChange的时机,如果配置了request则不会执行onChange
   */
  onChange?: (
    table?: any, //TableParams<RecordType>,
    formValue?: any, //FormValue,
    tabs?: any, //TabsParams,
  ) => void;
  /**
   * @desc 增强用于异步接口请求的配置,如果配置了dataSource,则该属性会失效
   */
  request?: (
    table?: any, //TableParams<RecordType>,
    formValue?: any, //FormValue,
    tabs?: any, //TabsParams,
  ) => Promise<{ list: RecordType[]; total: number }>;
  /**
   * @desc 增强字段request相关的配置
   */
  requestOptions?: {
    ready?: boolean;
    reFreshDep?: ReadonlyArray<unknown>;
    defaultPageIndex?: number;
    defaultPageSize?: number;
    onError?(): void;
  };

  // 可以自定义渲染表格结构内容
  children?: (nodes: RenderNode) => ReactNode;

  /**
   * @desc 操作列的按钮配置2.4.0版本新增配置
   */
  operate?: {
    text: string;
    onClick(record: RecordType, index: number): void;
    key: string;
    hidden?(record: RecordType, index: number): boolean;
    disabled?(record: RecordType, index: number): boolean;
  }[];

  /**
   * @desc 是否打印一些dev日志,组件开发人员使用的
   * @default {false}
   */
  devLog?: boolean;
}

const defaultPagination: MyPagination = {
  style: {
    margin: 0,
    paddingTop: 10,
    // paddingBottom: 16,
  },
  current: 1,
  pageSize: 10,
  defaultCurrent: 1,
  defaultPageSize: 10,
  showQuickJumper: true,
  showTotal: (n) => <>共{n}条</>,
  pageSizeOptions: [10, 15, 20, 30, 40, 50],
  showSizeChanger: true,
  size: 'small',
};

const defaultChildrenRender: NonNullable<YmTablePorps['children']> = function ({
  formNode,
  tableNode,
  tabsNode,
  toolBarNode,
}) {
  return (
    <>
      {formNode}
      {tabsNode}
      {toolBarNode}
      {tableNode}
    </>
  );
};

function YmTable<RecordType extends object = any, FormValue = any>(
  {
    wrapperStyle,
    columns: invokeColumns = [],
    dataSource: invokeDataSource,
    toolBar,
    searchForm,
    tabs,
    request,
    requestOptions,
    loading: invokeLoading,
    style,
    onChange,
    children = defaultChildrenRender,
    className,
    operate = [],
    expandable,
    ...props
  }: YmTablePorps<RecordType, FormValue>,
  ref: React.Ref<null>,
) {
  // request 请求的params类型
  type Params = {
    table: TableParams<RecordType>;
    tabs?: TabsParams;
  };

  type PreParams = Params & {
    form?: FormValue;
  };

  // 判断是否初始化代码
  const init = useRef<boolean>(false);

  // 内置用来内部强行刷新tabs 组件和 table 组件来重置时使用
  const [tableKeys] = useState(Math.random());

  // 内置展示table数据的字段,如果外面有则完全使用外面的
  const [dataSource, setDataSource] = useState<readonly RecordType[]>(
    invokeDataSource ?? [],
  );
  // 内置的loading加载动画,可以完全被外部替换
  const [insideLoading, setLoading] = useState(invokeLoading);

  const [filterHeight, setFilterHeight] = useState<number>(0);
  // 表格的ref dom
  // const tableRef = useRef<HTMLDivElement>(null);

  //为了兼容 expend时   filterHeight和dataSource.length都不变化导致useAntdTableScrollY，无法根据table tr行数的变化重新计算table布局的问题
  const [tableExpendKeys, setTableExpendKeys] = useState<readonly React.Key[]>(
    expandable?.expandedRowKeys ?? [],
  );

  const { getPrefixCls } = useContext(ConfigContext);
  // const prefixCls = getPrefixCls();
  // console.log('--table--prefixCls--:', prefixCls)

  // 如果外部控制后内部则完全失效
  const loading = useMemo(() => {
    return invokeLoading ?? insideLoading;
  }, [invokeLoading, insideLoading]);

  const pagination = useMemo<PaginationProps>(() => {
    const { current, pageSize, ...extra } = defaultPagination;
    return {
      current: requestOptions?.defaultPageIndex ?? current,
      pageSize: requestOptions?.defaultPageSize ?? pageSize,
      ...extra,
    };
  }, []);

  //key: '_operate',
  const insideColumns = useMemo(() => {
    const result = invokeColumns.map((columnItem) => {
      if (columnItem.key === '_operate') {
        let columnObj = {
          title: '操作',
          width: columnItem.width ?? 180,
          fixed: 'right',
          ...columnItem,
        };
        if (operate.length) {
          columnObj = {
            ...columnObj,
            render: (value: any, record: RecordType, index: number) => {
              return (
                <OpearteButtonGroup
                  items={operate
                    .filter((v) => {
                      v.hidden ??= () => false;
                      return !v.hidden(record, index);
                    })
                    .map(({ onClick, disabled = () => false, text, key }) => {
                      return {
                        text,
                        key,
                        onClick: () => {
                          onClick?.(record, index);
                        },
                        disabled: disabled(record, index),
                      };
                    })}
                />
              );
            },
          };
        }
        return columnObj;
      }
      return columnItem;
    });
    // console.log('--result--:', result);
    return result;
  }, [invokeColumns, operate]);

  // searchForm 查询表单实例
  const formRef = useRef<{ getFormInstance: () => FormInstance }>(null);

  // 上一次请求的参数
  const preParams = useRef<PreParams>({
    table: {
      page: {},
    },
  });

  // 请求参数记录state
  const [params, setParams] = useState<Params>(() => {
    return {
      table: {
        page: {
          current: pagination.current,
          pageIndex: pagination.current,
          pageSize: pagination.pageSize,
        },
      },
      tabs: tabs
        ? tabs.items?.find(
            (v) => v.key === (tabs.activeKey ?? tabs.defaultActiveKey),
          ) ?? tabs.items?.[0]
        : undefined,
    };
  });

  // 避免异步多次请求后结果与当前不一致
  const requestId = useRef(0);

  // 实际上是需要触发onChange的几个点
  const runRequest = function () {
    // 上一次请求的参数
    const pre = preParams.current;
    const formValue = formRef.current?.getFormInstance().getFieldsValue();
    if (
      (pre && pre.form && isObjectValueEqual(pre.form, formValue) === false) ||
      pre.tabs?.key !== params.tabs?.key
    ) {
      if (params.table.page) {
        params.table.page.pageIndex = 1;
        params.table.page.current = 1;
      }
    }

    // 重新给页码赋值
    pagination.current = params.table.page?.current;
    pagination.pageSize = params.table.page?.pageSize;

    onChange?.(params.table, formValue, params.tabs);
    if (
      request &&
      requestOptions?.ready !== false &&
      !invokeDataSource?.length
    ) {
      // 每次请求都会根据为该次请求设置一个随机id，如果结果与当前id不同则不处理结果
      requestId.current = Math.random();
      const lockId = requestId.current;
      setLoading(true);
      const interceptor = function <T extends unknown[]>(
        callback: (...params: T) => void,
      ) {
        return function (...params: T) {
          if (lockId === requestId.current) {
            callback(...params);
          }
        };
      };

      request(params.table, formValue, params.tabs)
        .then(
          interceptor(({ list = [], total }) => {
            // 设置数据
            setDataSource(list);
            // 设置总条数
            if (typeof total === 'number') {
              pagination.total = total;
            }
          }),
          interceptor(() => {
            requestOptions?.onError?.();
          }),
        )
        .finally(
          interceptor(() => {
            setLoading(false);
          }),
        );

      preParams.current.table = params.table;
      preParams.current.form = formValue;
      preParams.current.tabs = params.tabs;
    }
  };

  useEffect(() => {
    // 首次不要执行
    if (init.current && !invokeDataSource) {
      setParams((v) => {
        if (v.table.page) {
          v.table.page.current = 1;
          v.table.page.pageIndex = 1;
        }
        return { ...v };
      });
    }
  }, [invokeDataSource, ...(requestOptions?.reFreshDep ?? [])]);

  // 用户如果自行配置了dataSource,则request失效
  useEffect(() => {
    if (invokeDataSource) {
      setDataSource(invokeDataSource);
    } else {
      runRequest();
    }
  }, [invokeDataSource, params, requestOptions?.ready === false]);

  useImperativeHandle(ref, () => null, []);

  const {
    styles: { wrapper },
  } = useStyles();

  useEffect(() => {
    init.current = true;
  }, []);

  //

  // 监听的dom元素尺寸发生变化时
  const handleResize = (sizeInfo: SizeInfo, target: HTMLElement) => {
    const { height } = sizeInfo;
    if (target && height !== filterHeight) {
      setFilterHeight(height);
    }
  };

  const { tableRef, scrollY, cx } = useAntdTableScrollY(
    filterHeight,
    tableExpendKeys,
    dataSource.length,
  );

  const nodeInfo: RenderNode = {
    // 查询表格,如果有字段才有
    formNode: (
      <TableSearchForm
        ref={formRef}
        searchFrom={searchForm}
        onSubmit={() => setParams((v) => ({ ...v }))}
        onReset={() => setParams((v) => ({ ...v }))}
      />
    ),
    // tabs导航,也是配了才有
    tabsNode: (
      <TableTabs
        tabs={tabs}
        onTabsChange={(tabs) => setParams((v) => ({ ...v, tabs }))}
      />
    ),
    // toolbar占位行,默认有,可以通过配置清除
    toolBarNode: (
      <TableToolBar
        tableColumns={insideColumns}
        toolbar={toolBar}
        onRefresh={() => setParams((v) => ({ ...v }))}
      />
    ),
    tableNode: (
      <div
        className="ym-table-resize-parent"
        style={{ flexGrow: 1, overflow: 'hidden', minHeight: 100 }}
      >
        <YmResizeObserver
          isFullParent
          onResize={handleResize}
          rootClassName="ym-table-resize-content"
        >
          <Table
            className={cx(className)}
            tableLayout="fixed"
            scroll={{ y: scrollY, x: '100%' }}
            style={{ height: '100%', overflow: 'hidden', ...style }}
            pagination={pagination}
            ref={tableRef as Ref<any>}
            columns={(insideColumns || []).filter((v) => !v.hidden)}
            dataSource={dataSource}
            loading={loading}
            onChange={(page, filters, sorter, extra) => {
              setParams((v) => {
                return {
                  ...v,
                  table: {
                    page: {
                      pageIndex: page.current,
                      ...page,
                    },
                    filters,
                    sorter,
                    extra,
                  },
                };
              });
            }}
            expandable={{
              ...expandable,
              onExpandedRowsChange: (expandedKeys) => {
                expandable?.onExpandedRowsChange?.(expandedKeys);
                setTableExpendKeys(expandedKeys);
              },
            }}
            {...props}
            key={tableKeys}
          />
        </YmResizeObserver>
      </div>
    ),
  };

  if (props.devLog) {
    console.log(pagination);
  }

  return (
    <div
      className={wrapper}
      style={{
        ...wrapperStyle,
      }}
    >
      {children(nodeInfo)}
    </div>
  );
}

export default forwardRef(YmTable) as <
  RecordType extends object = any,
  FormValue = any,
>(
  props: YmTablePorps<RecordType, FormValue> & {
    ref?: Ref<null>;
  },
) => ReactElement;
